import 'dart:io';
import 'dart:typed_data';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:path_provider/path_provider.dart';

class StampImage {
  ///Create watermark to an existing image file [image] and custom Widget as the watermark item.
  ///You can customize the position using alignment
  static void create({
    required BuildContext context,
    required File image,
    required List<Widget> children,
    bool? saveFile = false,
    String? savePath,
    required Function(File) onSuccess,
  }) async {
    OverlayState? overlayState = Overlay.of(context, rootOverlay: true);
    OverlayEntry? entry;

    /// Wait until initial entries available
    while (true) {
      print('初始化等待中...');
      if (overlayState!.widget.initialEntries.length > 0) {
        break;
      }
    }
    OverlayEntry? lastEntry = overlayState.widget.initialEntries.first;
    entry = OverlayEntry(
      builder: (context) {
        return StampWidget(
            image: image,
            children: children,
            onSuccess: (file) {
              onSuccess(file);
              overlayState.widget.initialEntries.remove(entry);
              entry?.remove();
            });
      },
    );

    ///Set root overlay to top and watermark entry to below,
    ///we need this because we want to invisible the watermark entry
    overlayState.insert(entry, below: lastEntry);
  }
}

class StampWidget extends StatefulWidget {
  final List<Widget> children;
  final File? image;
  final bool? saveFile;
  final String? savePath;
  final Function(File) onSuccess;
  StampWidget({
    required this.children,
    required this.image,
    this.saveFile,
    this.savePath,
    required this.onSuccess,
  });

  @override
  _StampWidgetState createState() => _StampWidgetState();
}

class _StampWidgetState extends State<StampWidget> {
  ///Global frame key
  final frameKey = GlobalKey();

  ///Set widget from RepaintBoundary into uint8List
  ///and convert into File
  Future showResult() async {
    Uint8List? currentFrame = await getUint8List(frameKey);

    Directory? dir = Platform.isAndroid
        ? await getExternalStorageDirectory()
        : await getApplicationDocumentsDirectory();
    String? path = dir?.path;

    final file = createFile(
      '$path/stamp_image_${DateTime.now().millisecondsSinceEpoch.toString()}.png',
      currentFrame,
    );

    ///When user want to use saveFile, then
    ///it will saved to selected path location
    if (widget.saveFile == true && widget.savePath != null) {
      createFile(widget.savePath, currentFrame);
    }
    widget.onSuccess(file);
  }

  File createFile(String? path, Uint8List? data) {
    final file = File(path!);
    file.create();
    file.writeAsBytesSync(data!);
    return file;
  }

  ///Converting Widget to PNG
  Future<Uint8List?> getUint8List(GlobalKey widgetKey) async {
    await Future.delayed(Duration(milliseconds: 500));
    // RenderObject renderObject = await Future.sync(() async {
    //   RenderObject? renderObject;
    //   do {
    //     await Future.delayed(Duration(milliseconds: 5));
    //     print('获取renderObject中...');
    //     renderObject = widgetKey.currentContext?.findRenderObject();
    //     print('renderObject=$renderObject');
    //   } while (renderObject == null);
    //   return renderObject;
    // });
    RenderObject? renderObject = widgetKey.currentContext?.findRenderObject();
    RenderRepaintBoundary boundary = renderObject as RenderRepaintBoundary;
    print('width=${boundary.size.width}，height=${boundary.size.height}');
    //if (boundary.size.width == 0 || boundary.size.height == 0)
    //boundary.performLayout();
    var image = await boundary.toImage(pixelRatio: 2.0);
    ByteData? byteData = await (image.toByteData(
      format: ImageByteFormat.png,
    ));
    return byteData?.buffer.asUint8List();
  }

  ///Generating list of children for watermark item
  List<Widget> generateWidget() => widget.children.map((e) => e).toList();

  @override
  void initState() {
    super.initState();
    this.showResult();
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    print('调用dispose...');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: RepaintBoundary(
        key: frameKey,
        child: Container(
          child: Stack(
            children: [
              Container(
                child: Image.file(
                  widget.image!,
                  fit: BoxFit.cover,
                ),
              ),
              ...generateWidget()
            ],
          ),
        ),
      ),
    );
  }
}
